package com.ews.onlineexchange.service;

import java.io.IOException;
import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.util.Date;

import javax.enterprise.context.Conversation;
import javax.faces.context.ExceptionHandler;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.servlet.http.HttpServletResponse;

import com.ews.onlineexchange.dao.SimpleEntityManagerDao;
import com.ews.onlineexchange.exception.CustomExcepetionHandler;
import com.ews.onlineexchange.exception.ExceptionRedirector;
import com.ews.onlineexchange.model.DataEntity;
import com.ews.onlineexchange.model.User;

public class EntityHome<T extends DataEntity, PK extends Serializable> implements Serializable {

	protected static final String		RESULT_SAVED		= "saved";
	protected static final String		RESULT_DELETED		= "deleted";
	protected static final String		RESULT_CANCELLED	= "cancelled";

	/**
	 * 
	 */
	private static final long			serialVersionUID	= 1L;

	@Inject
	protected SimpleEntityManagerDao	entityManagerDao;

	@Inject
	protected Conversation				conversation;
	
	@Inject
	UserService							userService;
	private PK							id;
	private T							instance;

	public void initConversation() {
		if (conversation.isTransient()) {
			conversation.begin();
		}
	}

	public T getInstance() {
		if (instance == null) {
			if ( getId() != null) {
				instance = loadInstance();
			} else {
				instance = createInstance();
			}
		}
		return instance;
	}

	public void setInstance(T instance) {
		this.instance = instance;
	}

	public PK getId() {
		return id;
	}

	public void setId(PK id) {
		this.id = id;
	}

	public T loadInstance() {
		T find = entityManagerDao.find(getClassType(), getId());
		if(find == null){
			ExceptionRedirector exceptionRedirector = new ExceptionRedirector();
			exceptionRedirector.entityNotFoundExcepetionHandle();
		}
		return find;
	}

	public T createInstance() {
		try {
			return getClassType().newInstance();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	private Class<T> getClassType() {
		ParameterizedType parameterizedType = (ParameterizedType) getClass().getGenericSuperclass();
		return (Class<T>) parameterizedType.getActualTypeArguments()[0];
	}

	public boolean isManaged() {
		return getInstance().getId() != null;
	}
	
	public void flush() {
		if (!conversation.isTransient())
			conversation.end();
//		getEntityManager().flush();
	}

	public String saveAndFlush() {
		String result = save();
		if (!conversation.isTransient())
			conversation.end();
		return result;
	}
	
	@SuppressWarnings( "unchecked" )
	public String save() {
		User loginedUser = userService.getLoginedUser();
		if (isManaged()) {
			if ( loginedUser != null ) {
				getInstance().setUpdateBy( loginedUser.getUsername() );
				getInstance().setUpdateDate( new Date() );
			}
			entityManagerDao.updateObject(getInstance());
		} else {
			if ( loginedUser != null ) {
				getInstance().setCreateBy( loginedUser.getUsername() );
				getInstance().setCreateDate( new Date() );
			}
			this.instance = (T) entityManagerDao.createObject(getInstance());
		}
		return RESULT_SAVED;
	}

	public String delete() {
		entityManagerDao.deleteObject(getInstance());
		if (!conversation.isTransient())
			conversation.end();
		return RESULT_DELETED;
	}
	
	public void refresh() {
		setInstance( loadInstance() );
	}

	public String cancel() {
		if (!conversation.isTransient())
			conversation.end();
		return RESULT_CANCELLED;
	}

	public EntityManager getEntityManager() {
		return entityManagerDao.getEntityManager();
	}
	
	public SimpleEntityManagerDao getEntityManagerDao() {
		return entityManagerDao;
	}

	public Conversation getConversation() {
		return conversation;
	}

	public void setConversation(Conversation conversation) {
		this.conversation = conversation;
	}
	
	protected void updateOperator(User user) {
		getInstance().setLastUpdateDate(new Date());
		if(user != null) {
			if(isManaged())getInstance().setUpdateBy(user.getUsername());
			else getInstance().setCreateBy(user.getUsername());
		}
	}
}
